'''
Created on 08-02-2012

@author: cleve
'''
from pyaceOperations.matrix import *

from operator import itemgetter

from progressbar import Percentage, ProgressBar, Bar, ETA
from random import random, randint

class BusquedaDeGravedad(object):
    '''
    classdocs
    '''


    def __init__ (self, masaParticulas, universos, particulasDetectoras, acelerar, campo, matrizDistancia):
        """ Iniciar la clase """
        
        self.campo = campo
        self.c = 3e8
        self.acelerar = acelerar
        self.v = 0
        self.particulasDetectoras = particulasDetectoras
        self.universos = universos
        self.plano = 0
        self.grafo = matrizDistancia
        self.matrizDistancia = matrizDistancia
        self.nodos = len(self.matrizDistancia)
        self.matricesEspacioTemporales = MatrixClass(self.nodos, self.matrizDistancia, -1)
        self.mejoresItems = []
    
    
    def Evaluacion(self):
        pass
    
    
    def RunUniversos(self):
        """ Function doc
      
        @param None: None
        @return RETURN: DESCRIPTION
        """
        #Barra de progreso.
        self.widgets = ['ACE(TSP):', Percentage(), ' ', Bar(marker='#',left='[',right=']'), ' ', ETA(), ' ']
        self.pbar = ProgressBar(widgets=self.widgets, maxval=self.universos).start()
        #Fin barra de progreso.
        
        mejoresAristas = []
        mejoresDistanciasDeUniverso = []
        
        
        for universos in xrange(self.universos):
            
            curvatura = self.matricesEspacioTemporales.BigBang((self.nodos, self.nodos))
        
            for particulaDetectora in xrange(self.particulasDetectoras):
                
                #Selecciono particula al azar
                particulaInicial = randint(0, self.nodos - 1)
                  
                verticesDisponibes = range(self.nodos)
                  
                if self.acelerar == 'si':
                    self.v = random.randint(1, 2.99999999e8)
            
                while 1:
                    
                    resultadoParcial = []
                    #Aristas disponibles menos la de origen (origen,origen), esto es (origen,0),(origen,2),...,(origen,n-1)
                    aristas = [ (particulaInicial, nodo) for nodo in verticesDisponibes if nodo != particulaInicial and particulaInicial in verticesDisponibes]
                    
                    for seleccion_arista in aristas:
                      
                        #Masa en espacio-tiempo.
                        masaEspacioTiempo = float(curvatura[seleccion_arista[0]][seleccion_arista[1]])
                        
                        #Distancia obtenida del grafo de entrada.
                        distancia = float(self.grafo[seleccion_arista[0]][seleccion_arista[1]] ** 2)
                        
                        if self.v > 1.5e8:
                            calculo =  masaEspacioTiempo /  distancia* self.Factor(self.v)
                            
                        else:
                            calculo = masaEspacioTiempo / distancia
                          
                        resultadoParcial.append((calculo, seleccion_arista))
                        #Fin calculo de campo gravitatorio
                       
                    #Buscar la mejor seleccion, deja el mayor valor al final de la lista.
                    resultadoParcial.sort()
                    
                    
                    #Remuevo arista inicial.
                    verticesDisponibes.remove(particulaInicial)
                    
                    #Selecciono proxima arista, considerando la mejor seleccion anterior.
                    particulaInicial = resultadoParcial[-1][1][1]
                    mejorArista = resultadoParcial[-1][1]
                    
                    #Elimino mejor arista para no volver a seleccionarla.
                    aristas.remove(mejorArista)
                    
                    #Contruyo mejor solucion parcial.
                    mejoresAristas.append(mejorArista)
                    
                    if len(aristas) == 0:
                        break
                
                
                #Modificar curvatura del espacio
                curvatura = self.matricesEspacioTemporales.modificar_curvatura(curvatura)
                
                #Inicializo
                suma = 0
                  
                
            
                #Obtengo suma de distancias para tsp.
                for arista in mejoresAristas:
                    suma = self.grafo[arista[0]][arista[1]] + suma
                  
                #La linea siguiente obtiene la distancia total hasta el origen
                suma = suma + self.grafo[mejoresAristas[0][0]][mejoresAristas[len(mejoresAristas) - 1][1]]
                mejoresDistanciasDeUniverso.append(suma)  
              
                #Ordeno las mejores distancias (menor a mayor).
                mejoresDistanciasDeUniverso.sort()
                  
                #Guardo la mejor distancia con el conjunto de aristas.
                self.mejoresItems.append((mejoresDistanciasDeUniverso[0], mejoresAristas))
                  
                #Reinicio lista de aristas y mejores distancias universos para una proxima iteracion.
                mejoresDistanciasDeUniverso = []
                mejoresAristas = []
                
                #Con esto limito la cantidad de candidatos disponibles.
                self.mejoresItems = sorted(self.mejoresItems, key=itemgetter(0))[:2]
            
            self.pbar.update(universos+1)
        
        
        self.mejoresItems.sort()
            
        self.pbar.finish()
        
        return self.mejoresItems[0]
        
